package org.tlang.parser;

import org.tlang.ast.AST;
import org.tlang.ast.list.func.*;
import org.tlang.exception.ParseException;
import org.tlang.keywords.KeyWords;
import org.tlang.lexer.Lexer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 函数解析器
 */
public class FunctionParser extends StatementParser {
    public FunctionParser(Lexer lexer) {
        super(lexer);
    }

    /**
     * IDENTIFIER type_tag
     */
    private AST parameter() throws ParseException {
        List<AST> result = new ArrayList<>();
        result.add(identifier());
        result.add(typeTag());
        return new Parameter(result);
    }

    /**
     * parameter_list: "(" [ parameter {"," parameter} ] ")"
     */
    protected AST parameterList() throws ParseException {
        skip("(");
        List<AST> result = new ArrayList<>();
        while (true) {
            if (isIdentifier(")")) {
                skip(")");
                break;
            }

            if (!result.isEmpty()) {
                skip(",");
            }

            result.add(parameter());
        }

        return new ParameterList(result);
    }

    /**
     * function_define: "func" IDENTIFIER parameter_list type_tag block
     */
    protected AST functionDefine() throws ParseException {
        skip(KeyWords.FUNC);
        List<AST> result = new ArrayList<>();

        result.add(identifier());
        result.add(parameterList());
        result.add(typeTag());
        result.add(block());

        return new FunctionDefine(result);
    }

    /**
     * argument_list: "(" [ expr {"," expr} ] ")"
     */
    protected AST argumentList() throws ParseException {
        skip("(");
        List<AST> result = new ArrayList<>();

        while (true) {
            if (isIdentifier(")")) {
                skip(")");
                break;
            }

            if (!result.isEmpty()) {
                skip(",");
            }

            result.add(expr());
        }

        return new ArgumentList(result);
    }

    /**
     * 扩展primary，支持解析函数调用语句
     * example: func(1, 2)
     * primary: super_primary | IDENTIFIER [ argument_list ]
     */
    @Override
    protected AST primary() throws ParseException {
        AST primary = super.primary();
        if (isIdentifier("(")) {
            return new FunctionInvoker(Arrays.asList(primary, argumentList()));
        } else {
            return primary;
        }
    }
}
